package cn.edu.neu.lab603.cloudeval.strategy.policy

import cn.edu.neu.lab603.cloudeval.entity.{PhysicalMachine => Host}
import cn.edu.neu.lab603.cloudeval.monitor.HostUtilizationMonitor
import cn.edu.neu.lab603.math._

/** 使用 IQR 预测资源利用率的主机选择策略。
  *
  * Created by yfwz100 on 2016/11/9.
  */
class HostSelectionPolicyIQR(val utilMonitor: HostUtilizationMonitor,
                             val fallback: HostSelectionPolicyUtilizationBase,
                             val safety: Double = 1.0,
                             val capacityFactor: Double = 1.0)
  extends HostSelectionPolicyUtilizationBase(capacityFactor) with HistoryRecorder {

  /**
    * Checks if the host is over utilized, based on CPU utilization.
    *
    * @param host the host
    * @return true, if the host is over utilized; false otherwise
    */
  override def isOverloadHost(host: Host): Boolean = {
    val upperThreshold: Double = try {
      1 - safety * getHostUtilizationIqr(host)
    } catch {
      case _: IllegalArgumentException =>
        return fallback.isOverloadHost(host)
    }
    addHistoryEntry(host, upperThreshold)
    var totalRequestedMips: Double = 0
    for (vm <- host.getVMList) {
      totalRequestedMips += vm.getReqResMap("mips")
    }
    val utilization: Double = totalRequestedMips / host.capacity("mips")
    utilization > upperThreshold
  }

  /**
    * Gets the host CPU utilization percentage IQR.
    *
    * @param host the host
    * @return the host CPU utilization percentage IQR
    */
  @throws[IllegalArgumentException]
  protected def getHostUtilizationIqr(host: Host): Double = {
    val data: Array[Double] = utilMonitor.getHistory(host).toArray
    if (countNonZeroBeginning(data) >= 12) {
      // 12 has been suggested as a safe value
      iqr(data)
    } else {
      throw new IllegalArgumentException
    }
  }

  override def toString: String = "IQR"
}
